package net

import (
	"bytes"
	"encoding/json"
	"io"
	"mime/multipart"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"time"
)

func GetUrl(_url string, params url.Values) (string, error) {
	rurl, err := url.ParseRequestURI(_url)
	if err != nil {
		return _url, err
	}
	rurl.RawQuery = params.Encode()
	return rurl.String(), nil
}

func Get(_url string, header http.Header, params url.Values, timeout time.Duration) (*http.Response, error) {
	reqUrl, err := GetUrl(_url, params)
	if err != nil {
		return nil, err
	}
	req, err := http.NewRequest("GET", reqUrl, nil)
	if err != nil {
		return nil, err
	}
	if header != nil {
		req.Header = header
	}
	client := &http.Client{Timeout: timeout}
	return client.Do(req)
}

func GetJson(_url string, header http.Header, params url.Values, timeout time.Duration) (map[string]any, error) {
	rep, err := Get(_url, header, params, timeout)
	if err != nil {
		return nil, err
	}
	return response2json(rep)
}

// _url: 如果出现error：first path segment in URL cannot contain colon. 那么前面加上http://
// files: key-FormName,value-FileName
func Post(_url string, header http.Header, params map[string]string, files map[string]string, timeout time.Duration) (*http.Response, error) {
	bodyBuffer := &bytes.Buffer{}
	bodyWriter := multipart.NewWriter(bodyBuffer)

	for formName, fileName := range files {
		fileWriter, err := bodyWriter.CreateFormFile(formName, filepath.Base(fileName))
		if err != nil {
			return nil, err
		}
		f, _ := os.Open(fileName)
		defer f.Close()
		io.Copy(fileWriter, f)
	}

	for k, v := range params {
		err := bodyWriter.WriteField(k, v)
		if err != nil {
			return nil, err
		}
	}

	contentType := bodyWriter.FormDataContentType()
	bodyWriter.Close()

	req, err := http.NewRequest("POST", _url, bodyBuffer)
	if err != nil {
		return nil, err
	}
	if header != nil {
		req.Header = header
	}
	req.Header.Set("Content-Type", contentType)
	client := &http.Client{Timeout: timeout}
	return client.Do(req)
}

func PostJson(_url string, header http.Header, params map[string]string, files map[string]string, timeout time.Duration) (map[string]any, error) {
	rep, err := Post(_url, header, params, files, timeout)
	if err != nil {
		return nil, err
	}
	return response2json(rep)
}

func response2json(rep *http.Response) (map[string]any, error) {
	defer rep.Body.Close()
	body, err := io.ReadAll(rep.Body)
	if err != nil {
		return nil, err
	}
	var r map[string]any
	err = json.Unmarshal(body, &r)
	//convert f to map
	return r, err
}
